using System;
using ch.ethz.ssh2.util;
using Org.BouncyCastle.Math;
namespace ch.ethz.ssh2.packets
{

    /// <summary> TypesReader.
    /// 
    /// </summary>
    /// <author>  Christian Plattner
    /// </author>
    /// <version>  2.50, 03/15/10
    /// </version>
    public class TypesReader
    {
        internal byte[] arr;
        internal int pos = 0;
        internal int max = 0;

        public TypesReader(byte[] arr)
        {
            this.arr = arr;
            pos = 0;
            max = arr.Length;
        }

        public TypesReader(byte[] arr, int off)
        {
            this.arr = arr;
            this.pos = off;
            this.max = arr.Length;

            if ((pos < 0) || (pos > arr.Length))
                throw new System.ArgumentException("Illegal offset.");
        }

        public TypesReader(byte[] arr, int off, int len)
        {
            this.arr = arr;
            this.pos = off;
            this.max = off + len;

            if ((pos < 0) || (pos > arr.Length))
                throw new System.ArgumentException("Illegal offset.");

            if ((max < 0) || (max > arr.Length))
                throw new System.ArgumentException("Illegal length.");
        }

        public virtual int readByte()
        {
            if (pos >= max)
                throw new System.IO.IOException("Packet too short.");

            return (arr[pos++] & 0xff);
        }

        public virtual byte[] readBytes(int len)
        {
            if ((pos + len) > max)
                throw new System.IO.IOException("Packet too short.");

            byte[] res = new byte[len];

            Array.Copy(arr, pos, res, 0, len);
            pos += len;

            return res;
        }

        public virtual void readBytes(byte[] dst, int off, int len)
        {
            if ((pos + len) > max)
                throw new System.IO.IOException("Packet too short.");

            Array.Copy(arr, pos, dst, off, len);
            pos += len;
        }

        public virtual bool readBoolean()
        {
            if (pos >= max)
                throw new System.IO.IOException("Packet too short.");

            return (arr[pos++] != 0);
        }

        public virtual int readUINT32()
        {
            if ((pos + 4) > max)
                throw new System.IO.IOException("Packet too short.");

            return ((arr[pos++] & 0xff) << 24) | ((arr[pos++] & 0xff) << 16) | ((arr[pos++] & 0xff) << 8) | (arr[pos++] & 0xff);
        }

        public virtual long readUINT64()
        {
            if ((pos + 8) > max)
                throw new System.IO.IOException("Packet too short.");

            long high = ((arr[pos++] & 0xff) << 24) | ((arr[pos++] & 0xff) << 16) | ((arr[pos++] & 0xff) << 8) | (arr[pos++] & 0xff); /* sign extension may take place - will be shifted away =) */

            long low = ((arr[pos++] & 0xff) << 24) | ((arr[pos++] & 0xff) << 16) | ((arr[pos++] & 0xff) << 8) | (arr[pos++] & 0xff); /* sign extension may take place - handle below */

            return (high << 32) | (low & unchecked((int)0xffffffffL)); /* see Java language spec (15.22.1, 5.6.2) */
        }

        public virtual BigInteger readMPINT()
        {
            BigInteger b;

            byte[] raw = readByteString();

            if (raw.Length == 0)
                b = BigInteger.Zero;
            else
            {
                b = new BigInteger(raw);
            }

            return b;
        }

        public virtual byte[] readByteString()
        {
            int len = readUINT32();

            if ((len + pos) > max)
                throw new System.IO.IOException("Malformed SSH byte string.");

            byte[] res = new byte[len];
            Array.Copy(arr, pos, res, 0, len);
            pos += len;
            return res;
        }

        public virtual System.String readString(System.String charsetName)
        {
            int len = readUINT32();

            if ((len + pos) > max)
                throw new System.IO.IOException("Malformed SSH string.");

            System.String res = (charsetName == null) ? System.Text.Encoding.Default.GetString(arr, pos, len) : System.Text.Encoding.GetEncoding(charsetName).GetString(arr, pos, len);//new System.String(arr, pos, len) : new System.String(tempStr.ToCharArray(), pos, len);
            pos += len;

            return res;
        }

        public virtual System.String readString()
        {
            int len = readUINT32();

            if ((len + pos) > max)
                throw new System.IO.IOException("Malformed SSH string.");

            System.String res = StringEncoder.GetString(arr, pos, len);
            pos += len;

            return res;
        }

        public virtual System.String[] readNameList()
        {
            return Tokenizer.parseTokens(readString(), ',');
        }

        public virtual int remain()
        {
            return max - pos;
        }
    }
}